/**
 * @file common_sys_utils.c
 * @author Jio (hedajun@hzdusun.com)
 * @brief 操作 /sys/class 用户接口使用, 避免使用system调用
 * @version 0.1
 * @date 2023-10-12
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <utime.h>
#include "common_sys_utils.h"

RB_INT32 rb_sys_class_write(const char* sys_class_file_path, const char* write_cmd)
{
    FILE *fp = NULL; 
    if ((fp = fopen(sys_class_file_path, "w")) == NULL)  
    {
        DBG_LOG_ERR("Couldn't open class file[%s]\r\n", sys_class_file_path);
        return -1;
    }

    fprintf(fp, write_cmd);  
    fclose(fp);
    return 0;
}


RB_INT32 rb_sys_create_directory(const char *directory)
{
    struct stat st;
    if (stat(directory, &st) == -1) 
    {
        // 目录不存在，尝试创建目录
        if (mkdir(directory, 0777) == -1) 
        {
            DBG_LOG_ERR("Error creating directory");
            return RB_ERR;
        }
    } 
    else if (!S_ISDIR(st.st_mode)) 
    {
        // 有个文件于需要创建的目录名相同 
        const char *filename = directory;
        if (unlink(filename) == -1) 
        {
            DBG_LOG_ERR("Error deleting file");
            return RB_ERR;
        }
        else
        {
            if (mkdir(directory, 0777) == -1) 
            {
                DBG_LOG_ERR("Error creating directory");
                return RB_ERR;
            }
        }
    }

    return RB_OK;
}

RB_INT32 rb_sys_gpio_set(RB_INT32 gpio, RB_INT32 value)
{
    char gpio_value[128];
    RB_INT32 iRet = R_OK;

    snprintf(gpio_value, sizeof(gpio_value), "/sys/class/gpio/gpio%d/value", gpio);
    if (access(gpio_value, F_OK) != 0)
    {
        char gpio_cmd[128];
        char gpio_direction[128];

        snprintf(gpio_cmd, sizeof(gpio_cmd), "%d", gpio);
        rb_sys_class_write("/sys/class/gpio/export", gpio_cmd);

        snprintf(gpio_direction, sizeof(gpio_direction), "/sys/class/gpio/gpio%d/direction", gpio);
        if ((access(gpio_direction, F_OK) != 0)
            || (access(gpio_value, F_OK) != 0))
        {
            DBG_LOG_ERR("export gpio[%d] faild", gpio);
            return RB_ERR;
        }

        rb_sys_class_write(gpio_direction, "out");
    }

    iRet = rb_sys_class_write(gpio_value, (value == 0) ? "0" : "1");
    return  (iRet == 0) ? RB_OK : RB_ERR;
}

RB_INT32 rb_sys_create_directory_recursive(const char *directory) 
{
    char tmp[256];
    char *p = NULL;
    size_t len;

    snprintf(tmp, sizeof(tmp), "%s", directory);
    len = strlen(tmp);

    if (tmp[len - 1] == '/')
        tmp[len - 1] = '\0';

    for (p = tmp + 1; *p; p++) 
    {
        if (*p == '/') 
        {
            *p = '\0';
            if (rb_sys_create_directory(tmp) == RB_ERR) 
            {
                DBG_LOG_ERR("Error creating directory [%s]", tmp);
                return RB_ERR;
            }
            *p = '/';
        }
    }

    if (rb_sys_create_directory(tmp) == RB_ERR) 
    {
        DBG_LOG_ERR("Error creating directory [%s]", tmp);
        return RB_ERR;
    }

    return RB_OK;
}

RB_INT32 rb_sys_file_modify_time_compare(const char *file1, const char *file2) 
{
    struct stat file1_stat;
    struct stat file2_stat;

    if (stat(file1, &file1_stat) == 0) 
    {
        if (stat(file2, &file2_stat) == 0)
        {
            if (file2_stat.st_mtime > file1_stat.st_mtime) 
            {
                return RB_SYS_FILE_TIME_COMPARE_LITTLE;
            }
            else if (file2_stat.st_mtime == file1_stat.st_mtime) 
            {
                return RB_SYS_FILE_TIME_COMPARE_EQUEAL;
            }
            else 
            {
                return RB_SYS_FILE_TIME_COMPARE_LARGER;
            }
        }
        else 
        {
            // DBG_LOG_ERR("Failed to stat destination file [%s].", file2);
            return RB_SYS_FILE_TIME_COMPARE_DEST_ERROR;
        }
    } 
    else 
    {
        // DBG_LOG_ERR("Failed to stat source file [%s].", file1);
        return RB_SYS_FILE_TIME_COMPARE_SOURE_ERROR;
    }
}


RB_INT32 rb_sys_file_sync_cp(const char *file1, const char *file2)
{
    struct stat file1_stat;

    if (stat(file1, &file1_stat) == 0) 
    {
        FILE* source_file = fopen(file1, "rb");
        if (source_file == NULL) 
        {
            DBG_LOG_ERR("Failed to open source file [%s].", file1);
            return RB_ERR;
        }

        FILE* destination_file = fopen(file2, "wb");
        if (destination_file == NULL) 
        {
            DBG_LOG_ERR("Failed to create destination file.[%s]\n", file2);
            fclose(source_file);
            return RB_ERR;
        }

        // 逐块读取源文件内容并写入目标文件
        char buffer[1024];
        size_t bytes_read;
        while ((bytes_read = fread(buffer, 1, sizeof(buffer), source_file)) > 0) 
        {
            fwrite(buffer, 1, bytes_read, destination_file);
        }

        // 关闭文件
        fclose(source_file);
        fclose(destination_file);

        struct utimbuf file_times;
        file_times.actime = 0;
        file_times.modtime = file1_stat.st_mtime;
        if (utime(file2, &file_times) == 0)
        {
            return RB_OK;
        }
        else 
        {
            DBG_LOG_ERR("Failed to sync destination file [%s] modify time.", file2);
        }
    } 
    else 
    {
        DBG_LOG_ERR("Failed to stat source file [%s].", file1);
    }

    return RB_ERR;
}